package main

import "fmt"

type trunk struct {
    xmit    [16]chan pulse      // 发送通道数组，长度为16
    recv    []chan pulse        // 接收通道切片
    started bool                // 标记该 trunk 是否已启动
    update  chan int            // 更新通知通道
}

var dtrays [20]trunk  // 包含20个 trunk 实例的数组
var ctrays [121]trunk // 包含121个 trunk 实例的数组

func treset(t *trunk) {
    // 遍历所有发送通道并将其设置为 nil
    for i, _ := range t.xmit {
        t.xmit[i] = nil
    }

    // 清空接收通道切片
    t.recv = nil

    // 重置启动标志
    t.started = false

    // 如果更新通道不为空，则发送 -1 信号并清空更新通道
    if t.update != nil {
        t.update <- -1
        t.update = nil
    }
}

// trayreset 函数重置所有 dtrays 和 ctrays 中的 trunk 实例。
func trayreset() {
    // 遍历 dtrays 数组中的每个 trunk 实例，并调用 treset 函数进行重置
    for i, _ := range dtrays {
        treset(&dtrays[i])
    }
    // 遍历 ctrays 数组中的每个 trunk 实例，并调用 treset 函数进行重置
    for i, _ := range ctrays {
        treset(&ctrays[i])
    }
}

// handshake 函数用于通过指定通道 ch 发送一个脉冲信号，并等待响应。
func handshake(val int, ch chan pulse, resp chan int) {
    if ch != nil { // 如果通道 ch 不为空
        ch <- pulse{val, resp} // 发送一个包含 val 和 resp 通道的脉冲信号
        <-resp // 等待从 resp 通道接收到响应
    }
}

// dotrunk 函数处理一个 trunk 实例的所有发送和接收操作。
func dotrunk(t *trunk) {
    var x, p pulse

    p.resp = make(chan int) // 初始化脉冲响应通道

    for {
        select {
        case q := <-t.update: // 监听更新通道
            if q == -1 { // 如果收到 -1 信号，表示需要退出
                return
            }
            continue // 继续下一次循环

        // 监听所有发送通道 (xmit[0] 到 xmit[15])，接收脉冲信号
        case x = <-t.xmit[0]:
        case x = <-t.xmit[1]:
        case x = <-t.xmit[2]:
        case x = <-t.xmit[3]:
        case x = <-t.xmit[4]:
        case x = <-t.xmit[5]:
        case x = <-t.xmit[6]:
        case x = <-t.xmit[7]:
        case x = <-t.xmit[8]:
        case x = <-t.xmit[9]:
        case x = <-t.xmit[10]:
        case x = <-t.xmit[11]:
        case x = <-t.xmit[12]:
        case x = <-t.xmit[13]:
        case x = <-t.xmit[14]:
        case x = <-t.xmit[15]:

        }

        p.val = x.val // 将接收到的脉冲值赋给 p

        if x.val != 0 { // 如果接收到的脉冲值不为 0
            needresp := 0 // 计数器，用于跟踪需要等待的响应数量

            // 遍历所有的接收通道
            for _, c := range t.recv {
                if c != nil { // 如果当前接收通道不为空
                    pulseloop:
                    for {
                        select {
                        case c <- p: // 尝试将脉冲信号发送到当前接收通道
                            needresp++ // 增加需要等待的响应数量
                            break pulseloop // 跳出内层循环
                        case <-p.resp: // 如果从响应通道接收到信号
                            needresp-- // 减少需要等待的响应数量
                        }
                    }
                }
            }

            // 等待所有需要的响应
            for needresp > 0 {
                <-p.resp // 从响应通道接收信号
                needresp-- // 减少需要等待的响应数量
            }
        }

        // 如果原始脉冲信号有响应通道，则发送响应
        if x.resp != nil {
            x.resp <- 1
        }
    }
}

// trunkxmit 函数用于将一个脉冲发送通道 ch 添加到指定的 trunk 实例中。
func trunkxmit(ilk, n int, ch chan pulse) {
    var t *trunk // 定义一个指向 trunk 结构体的指针

    // 根据 ilk 的值选择 dtrays 或 ctrays 数组中的 trunk 实例
    if ilk == 0 {
        t = &dtrays[n]
    } else {
        t = &ctrays[n]
    }

    // 如果该 trunk 实例尚未启动，则初始化并启动它
    if !t.started {
        t.update = make(chan int)
        go dotrunk(t) // 启动一个新的 goroutine 来处理 trunk 实例
        t.started = true
    }

    // 遍历所有发送通道，找到第一个空闲的通道并分配给 ch
    for i, c := range t.xmit {
        if c == nil {
            t.xmit[i] = ch
            t.update <- 1 // 发送更新信号，通知状态变化
            return
        }
    }

    // 如果没有找到空闲的发送通道，则打印错误信息
    fmt.Printf("Too many transmitters on %d:%d\n", ilk, n)
}

// trunkrecv 函数用于将一个脉冲接收通道 ch 添加到指定的 trunk 实例中。
func trunkrecv(ilk, n int, ch chan pulse) {
    var t *trunk // 定义一个指向 trunk 结构体的指针

    // 根据 ilk 的值选择 dtrays 或 ctrays 数组中的 trunk 实例
    if ilk == 0 {
        t = &dtrays[n]
    } else {
        t = &ctrays[n]
    }

    // 如果接收通道切片为空，则初始化它
    if t.recv == nil {
        t.recv = make([]chan pulse, 0, 20) // 初始化容量为20的切片
    }

    // 遍历所有接收通道，找到第一个空闲的通道并分配给 ch
    for i, c := range t.recv {
        if c == nil {
            t.recv[i] = ch
            return
        }
    }

    // 如果接收通道切片未满，则直接追加新的接收通道
    if len(t.recv) != cap(t.recv) {
        t.recv = append(t.recv, ch)
    }
}
